Header file variant.hpp

namespace type_safe
{
    template <typename T>
    using variant_type = union_type<T>;
    
    template <typename ... Ts>
    using variant_types = union_types<Ts...>;
    
    struct nullvar_t;
    
    constexpr nullvar_t nullvar;
    
    template <class VariantPolicy, typename HeadT, typename ... TailT>
    class basic_variant;
    
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator==(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator!=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator==(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator!=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator<(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator<=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator>(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator>=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    
    template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
    void with(basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);
    template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
    void with(const basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);
    template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
    void with(basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);
    template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
    void with(const basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);
    
    template <typename Fallback>
    class fallback_variant_policy;
    
    template <typename Fallback, typename ... OtherTypes>
    using fallback_variant = basic_variant<fallback_variant_policy<Fallback>, Fallback, OtherTypes...>;
    
    class optional_variant_policy;
    
    using rarely_empty_variant_policy = 'hidden';
    
    using never_empty_variant_policy = 'hidden';
    
    template <typename ... Types>
    using variant = typename detail::select_variant_policy<Types...>::type;
}

Alias template type_safe::variant_type [variant]

template <typename T>
using variant_type = union_type<T>;

Convenience alias for ts::union_type.

Alias template type_safe::variant_types [variant]

template <typename ... Ts>
using variant_types = union_types<Ts...>;

Convenience alias for ts::union_types.

Struct type_safe::nullvar_t [variant]

struct nullvar_t
{
    constexpr nullvar_t();
};

Tag type to mark a ts::basic_variant without a value.

Variable type_safe::nullvar [variant]

constexpr nullvar_t nullvar;

Tag object of type ts::nullvar_t.

Class template type_safe::basic_variant [variant]

template <class VariantPolicy, typename HeadT, typename ... TailT>
class basic_variant
{
public:
    using types = typename union_t::types;
    
    using type_id = typename union_t::type_id;
    
    using allow_empty = typename VariantPolicy::allow_empty;
    
    static constexpr type_id invalid_type = union_t::;
    
    basic_variant() noexcept;
    basic_variant(nullvar_t) noexcept;
    
    basic_variant(const basic_variant&) = default;
    basic_variant(basic_variant&&) = default;
    
    template <typename T, typename ... Args>
    basic_variant(variant_type<T> type, Args&&... args);
    
    template <typename T, typename = detail::enable_variant_type<union_t, T, T&&>>
    basic_variant(T&& obj);
    
    basic_variant(const tagged_union<HeadT, TailT...>& u);
    basic_variant(tagged_union<HeadT, TailT...>&& u);
    
    ~basic_variant() noexcept = default;
    
    basic_variant& operator=(const basic_variant&) = default;
    
    basic_variant& operator=(basic_variant&&) = default;
    
    basic_variant& operator=(nullvar_t) noexcept;
    
    template <typename T>
    basic_variant& operator=(T&& obj);
    
    friend void swap(basic_variant& a, basic_variant& b) noexcept('hidden');
    
    void reset() noexcept;
    
    template <typename T, typename Arg>
    void emplace(variant_type<T> type, Arg&& arg);
    
    template <typename T, typename ... Args>
    void emplace(variant_type<T> type, Args&&... args);
    
    type_id type() const noexcept;
    
    bool has_value() const noexcept;
    operator bool() const noexcept;
    bool has_value(variant_type<nullvar_t>) const noexcept;
    
    template <typename T>
    bool has_value(variant_type<T> type) const noexcept;
    
    nullvar_t value(variant_type<nullvar_t>) const noexcept;
    
    template <typename T, typename = enable_valid<T>>
    T& value(variant_type<T> type) & noexcept;
    
    template <typename T>
    const T& value(variant_type<T> type) const & noexcept;
    template <typename T>
    T&& value(variant_type<T> type) && noexcept;
    template <typename T>
    const T&& value(variant_type<T> type) const && noexcept;
    
    optional_ref<const nullvar_t> optional_value(variant_type<nullvar_t>) const noexcept;
    
    template <typename T>
    optional_ref<T> optional_value(variant_type<T> type) & noexcept;
    
    template <typename T>
    optional_ref<const T> optional_value(variant_type<T> type) const & noexcept;
    template <typename T>
    optional_xvalue_ref<T> optional_value(variant_type<T> type) && noexcept;
    template <typename T>
    optional_xvalue_ref<const T> optional_value(variant_type<T> type) const && noexcept;
    
    template <typename T, typename U>
    T value_or(variant_type<T> type, U&& other) const &;
    template <typename T, typename U>
    T value_or(variant_type<T> type, U&& other) &&;
    
    template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::copy_constructible::value, Dummy>::type>
    basic_variant map(Functor&& f, Args&&... args) const &;
    template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::move_constructible::value, Dummy>::type>
    basic_variant map(Functor&& f, Args&&... args) &&;
};

An improved union storing at most one of the given types at a time (or possibly none).

It is an improved version of std::variant. A big problem with variant is implementing the operation that changes the type. It has to destroy the old value and then create the new one. But how to handle an exception when creating the new type? There are multiple ways of handling this, so it is outsourced in a policy. The variant policy is a class that must have the following members:

Default constructor type_safe::basic_variant::basic_variant::basic_variant

(1)  basic_variant() noexcept;

(2)  basic_variant(nullvar_t) noexcept;

Effects: Initializes the variant to the empty state.

Notes: This constructor only participates in overload resolution, if the policy allows an empty variant.

Copy constructor type_safe::basic_variant::basic_variant

(1)  basic_variant(const basic_variant&) = default;

(2)  basic_variant(basic_variant&&) = default;

Copy (1)/move (2) constructs a variant.

Effects: If the other variant is not empty, it will call ts::copy (1) or ts::move (2). \throws Anything thrown by the copy (1)/move (2) constructor. \notes This constructor only participates in overload resolution, if all types are copy (1)/move (2) constructible.

Notes: The move constructor only moves the stored value, and does not make the other variant empty.

Function template type_safe::basic_variant::basic_variant

template <typename T, typename ... Args>
basic_variant(variant_type<T> type, Args&&... args);

Initializes it containing a new object of the given type.

Effects: Creates it by calling Ts constructor with the perfectly forwarded arguments.

Throws: Anything thrown by Ts constructor.

Notes: This constructor does not participate in overload resolution, unless T is a valid type for the variant and constructible from the arguments.

Function template type_safe::basic_variant::basic_variant

template <typename T, typename = detail::enable_variant_type<union_t, T, T&&>>
basic_variant(T&& obj);

Initializes it with a copy of the given object.

Effects: Same as the type + argument constructor called with the decayed type of the argument and the object perfectly forwarded. \throws Anything thrown by Ts copy/move constructor. \notes This constructor does not participate in overload resolution, unless T is a valid type for the variant and copy/move constructible. \param 1 \exclude

Constructor type_safe::basic_variant::basic_variant

(1)  basic_variant(const tagged_union<HeadT, TailT...>& u);

(2)  basic_variant(tagged_union<HeadT, TailT...>&& u);

Initializes it from a ts::tagged_union.

Effects: Copies the currently stored type of the union into the variant by calling the copy (1)/move (2) constructor of the stored type.

Throws: Anything thrown by the selected copy (1)/move (2) constructor.

Requires: If the variant policy does not allow the empty state, the union must not be empty.

Destructor type_safe::basic_variant::~basic_variant

~basic_variant() noexcept = default;

Effects: Destroys the currently stored value, if there is any.

Assignment operator type_safe::basic_variant::operator=

basic_variant& operator=(const basic_variant&) = default;

Copy (1)/move (2) assigns a variant.

Effects: If the other variant is empty, makes this one empty as well. Otherwise let the other variant contains an object of type T. If this variant contains the same type and there is a copy (1)/move (2) assignment operator available, assigns the object to this object. Else forwards to the variant policy's change_value() function. \throws Anything thrown by either the copy (1)/move (2) assignment operator or copy (1)/move (2) constructor. If the assignment operator throws, the variant will contain the partially assigned object. If the constructor throws, the state depends on the variant policy. \notes This function does not participate in overload resolution, unless all types are copy (1)/move (2) constructible. \group copy_move_assign

Assignment operator type_safe::basic_variant::operator=

(1)  basic_variant& operator=(basic_variant&&) = default;

Assignment operator type_safe::basic_variant::operator=::operator=

basic_variant& operator=(nullvar_t) noexcept;

Alias for reset().

Assignment operator type_safe::basic_variant::operator=

template <typename T>
basic_variant& operator=(T&& obj);

Same as the single argument emplace().

Effects: Changes the value to a copy of obj.

Throws: Anything thrown by Ts copy/move constructor.

Notes: This function does not participate in overload resolution, unless T is a valid type for the variant and copy/move constructible.

Function type_safe::swap

friend void swap(basic_variant& a, basic_variant& b) noexcept('hidden');

Swaps two variants.

Effects: There are four cases:

Effects: In either case, it will only call the swap() function or the move constructor.

Throws: Anything thrown by the swap function, in which case both variants contain the partially swapped values, or the mvoe constructor, in which case the exact behavior depends on the variant policy.

Function template type_safe::basic_variant::reset::reset

void reset() noexcept;

Effects: Destroys the stored value in the variant, if any.

Notes: This function only participate in overload resolution, if the variant policy allows the empty state.

Function template type_safe::basic_variant::emplace

template <typename T, typename Arg>
void emplace(variant_type<T> type, Arg&& arg);

Changes the value to a new object of the given type.

Effects: If the variant contains an object of the same type, assigns the argument to it. Otherwise behaves as the other emplace version.

Throws: Anything thrown by the chosen assignment operator or the other emplace(). If the assignment operator throws, the variant contains a partially assigned object. Otherwise it depends on the variant policy.

Notes: This function does not participate in overload resolution, unless T is a valid type for the variant and assignable from the argument without creating an additional temporary.

Function template type_safe::basic_variant::emplace

template <typename T, typename ... Args>
void emplace(variant_type<T> type, Args&&... args);

Changes the value to a new object of given type.

Effects: If variant is empty, creates the object directly in place by perfectly forwarding the arguments. Otherwise it forwards to the variant policy's change_value() function.

Throws: Anything thrown by Ts constructor or possibly move constructor. If the variant was empty before, it is still empty afterwards. Otherwise the state depends on the policy.

Notes: This function does not participate in overload resolution, unless T is a valid type for the variant and constructible from the arguments.

Function type_safe::basic_variant::type

type_id type() const noexcept;

Returns: The type id representing the type of the value currently stored in the variant.

Notes: If it does not have a value stored, returns invalid_type.

Function type_safe::basic_variant::has_value

(1)  bool has_value() const noexcept;

(2)  operator bool() const noexcept;

(3)  bool has_value(variant_type<nullvar_t>) const noexcept;

Returns: true if the variant currently contains a value, false otherwise.

Notes: Depending on the variant policy, it can be guaranteed to return true all the time.

Function template type_safe::basic_variant::has_value

template <typename T>
bool has_value(variant_type<T> type) const noexcept;

Returns: true if the variant currently stores an object of type T, false otherwise.

Notes: T must not necessarily be a type that can be stored in the variant.

Function type_safe::basic_variant::value

nullvar_t value(variant_type<nullvar_t>) const noexcept;

Returns: A copy of ts::nullvar.

Requires: The variant must be empty.

Function template type_safe::basic_variant::value

template <typename T, typename = enable_valid<T>>
T& value(variant_type<T> type) & noexcept;

Returns: A (const) lvalue (1, 2)/rvalue (3, 4) reference to the stored object of the given type. \requires The variant must currently store an object of the given type, i.e. has_value(type) must return true. \group value \param 1 \exclude

Function template type_safe::basic_variant::value

(1)  template <typename T>
     const T& value(variant_type<T> type) const & noexcept;

(2)  template <typename T>
     T&& value(variant_type<T> type) && noexcept;

(3)  template <typename T>
     const T&& value(variant_type<T> type) const && noexcept;

Function type_safe::basic_variant::optional_value

optional_ref<const nullvar_t> optional_value(variant_type<nullvar_t>) const noexcept;

Returns: A ts::optional_ref to ts::nullvar. If the variant is not empty, returns a null reference.

Function template type_safe::basic_variant::optional_value

template <typename T>
optional_ref<T> optional_value(variant_type<T> type) & noexcept;

Returns: A (const) ts::optional_ref (1, 2)/ts::optional_xvalue_ref to the stored value of given type. If it stores a different type, returns a null reference. \group optional_value

Function template type_safe::basic_variant::optional_value

(1)  template <typename T>
     optional_ref<const T> optional_value(variant_type<T> type) const & noexcept;

(2)  template <typename T>
     optional_xvalue_ref<T> optional_value(variant_type<T> type) && noexcept;

(3)  template <typename T>
     optional_xvalue_ref<const T> optional_value(variant_type<T> type) const && noexcept;

Function template type_safe::basic_variant::value_or

(1)  template <typename T, typename U>
     T value_or(variant_type<T> type, U&& other) const &;

(2)  template <typename T, typename U>
     T value_or(variant_type<T> type, U&& other) &&;

Returns: If the variant currently stores an object of type T, returns a copy of that by copy (1)/move (2) constructing. Otherwise returns other converted to T.

Throws: Anything thrown by Ts copy (1)/move (2) constructor or the converting constructor.

Notes: T must not necessarily be a type that can be stored in the variant.

Notes: This function does not participate in overload resolution, unless T is copy (1)/move (2) constructible and the fallback convertible to T.

Function template type_safe::basic_variant::map

(1)  template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::copy_constructible::value, Dummy>::type>
     basic_variant map(Functor&& f, Args&&... args) const &;

(2)  template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::move_constructible::value, Dummy>::type>
     basic_variant map(Functor&& f, Args&&... args) &&;

Maps a variant with a function.

Effects: If the variant is not empty, calls the function using either std::forward<Functor>(f)(current-value, std::forward<Args>(args)...) or member call syntax (current-value.*std::forward<Functor>(f))(std::forward<Args>(args)...). If those two expressions are both ill-formed, does nothing. \returns A new variant of the same type. It contains nothing, if *this contains nothing. Otherwise, if the function was called, it contains the result of the function. Otherwise, it is a copy of the current variant. \throws Anything thrown by the function or copy/move constructor, in which case the variant will be left unchanged, unless the object was already moved into the function and modified there.

Requires: The result of the function - if it is called - can be stored in the variant.

Notes: (1) will use the copy constructor, (2) will use the move constructor. The function does not participate in overload resolution, if copy (1)/move (2) constructors are not available for all types.


Comparison operator type_safe::operator==

template <class VariantPolicy, typename Head, typename ... Types>
bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

Compares a ts::basic_variant with ts::nullvar.

A variant compares equal to nullvar, when it does not have a value. A variant compares never less to nullvar, nullvar compares less only if the variant has a value. The other comparisons behave accordingly. \group variant_comp_null \module variant

Comparison operator type_safe::operator==

(1)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator==(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(2)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

(3)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator!=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(4)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

(5)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(6)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

(7)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(8)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

(9)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(10)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

(11)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

Comparison operator type_safe::operator==

template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

Compares a ts::basic_variant with a value.

A variant compares equal to a value, if it contains an object of the same type and the object compares equal. A variant compares less to a value, if - when it has a different type - the type id compares less than the type id of the value, or - when it has the same type - the object compares less to the value. The other comparisons behave accordingly. \notes The value must not necessarily have a type that can be stored in the variant. \group variant_comp_t \module variant

Comparison operator type_safe::operator==

(1)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator==(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(2)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

(3)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator!=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(4)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

(5)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator<(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(6)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

(7)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator<=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(8)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

(9)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator>(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(10)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

(11)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator>=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

Comparison operator type_safe::operator==

template <class VariantPolicy, typename Head, typename ... Types>
bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

Compares two ts::basic_variants.

They compare equal if both store the same type (or none) and the stored object compares equal. A variant is less than another if they store mismatched types and the type id of the first is less than the other, or if they store the same type and the stored object compares less. The other comparisons behave accordingly. \module variant \group variant_comp

Comparison operator type_safe::operator!=

(1)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(2)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(3)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(4)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(5)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

Function template type_safe::with [variant]

(1)  template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
     void with(basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);

(2)  template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
     void with(const basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);

(3)  template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
     void with(basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);

(4)  template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
     void with(const basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);

Effects: If the variant is empty, does nothing. Otherwise let the variant contain an object of type T. If the functor is callable for the T, calls its operator() passing it the stored object. Else does nothing.

Class template type_safe::fallback_variant_policy [variant]

template <typename Fallback>
class fallback_variant_policy
{
public:
    using allow_empty = std::false_type;
    
    template <typename T, typename ... Types, typename ... Args>
    static void change_value(union_type<T> type, tagged_union<Types...>& storage, Args&&... args);
};

A variant policy for ts::basic_variant that uses a fallback type.

When changing the type of the variant throws an exception, the variant will create an object of the fallback type instead. The variant will never be empty.

Requires: Fallback must be nothrow default constructible and a type that can be stored in the variant.

Alias template type_safe::fallback_variant [variant]

template <typename Fallback, typename ... OtherTypes>
using fallback_variant = basic_variant<fallback_variant_policy<Fallback>, Fallback, OtherTypes...>;

A ts::basic_variant using the ts::fallback_variant_policy.

This is a variant that is never empty, where exceptions on changing the type leaves it with a default-constructed object of the Fallback type.

Requires: Fallback must be nothrow default constructible.

Class type_safe::optional_variant_policy [variant]

class optional_variant_policy
{
public:
    using allow_empty = std::true_type;
    
    template <typename T, typename ... Types, typename ... Args>
    static void change_value(union_type<T> type, tagged_union<Types...>& storage, Args&&... args);
};

A variant policy for ts::basic_variant that creates a variant with explicit empty state.

It allows an empty variant explicitly. When changing the type of the variant throws an exception, the variant will be left in that empty state.

Type alias type_safe::rarely_empty_variant_policy [variant]

using rarely_empty_variant_policy = 'hidden';

A variant policy for ts::basic_variant that creates a variant which is rarely empty.

When changing the type of the variant, it will use a the move constructor with a temporary. If the move constructor throws, the variant will be left in the empty state. Putting it into the empty state explicitly is not allowed.

Type alias type_safe::never_empty_variant_policy [variant]

using never_empty_variant_policy = 'hidden';

A variant policy for ts::basic_variant that creates a variant which is never empty.

Similar to ts::rarely_empty_variant_policy but when the move constructor throws, it calls std::terminate().

Alias template type_safe::variant [variant]

template <typename ... Types>
using variant = typename detail::select_variant_policy<Types...>::type;

A ts::basic_variant with the recommended default semantics.

If the first type is ts::nullvar_t it will use the ts::optional_variant_policy, which explicitly allows the empty state. Otherwise it will use the ts::rarely_empty_variant_policy where it tries to avoid the empty state as good as possible.

Notes: If you pass ts::nullvar_t as the first type, it is not actually one of the types that can be stored in the variant, but a tag to enable the empty state.